/**
 * build_project
 * <p>
 * Copyright 2014 cayden.cn, Inc. All rights reserved.
 *
 * @author Administrator
 * @date 2021-06-21 14:58
 */
package com.cayden.config.project.componets.db;

import com.cayden.config.boot.Apps;
import com.cayden.config.project.componets.aop.CheckDataSourceHandleAop;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import javax.sql.DataSource;
import java.util.*;

/**
 *
 * @author cayden
 * @date 2021-06-21 14:58
 */
@Configuration
@EnableConfigurationProperties({DruidProperties.class,MultipleDataSourcesProperties.class})
@ConditionalOnProperty(value = DruidProperties.ENABLE_KEY, matchIfMissing = true)
@Slf4j
public class JdbcAutoConfig{

    @Autowired
    private DruidProperties druidProperties;

    @Autowired
    private MultipleDataSourcesProperties multipleDataSourcesProperties;

    public JdbcAutoConfig(){
        log.info("init Jdbc config");
    }

    /**
     * 数据源
     */
    @ConditionalOnProperty(name = "cayden.multiple.enable", havingValue = "true")
    @Bean(initMethod = "init", destroyMethod = "close")
    @ConditionalOnMissingBean
    public MultipleDataSource druidDataSource() {
        String dbDriver = multipleDataSourcesProperties.getDriver();
        Integer dbInitialSize = multipleDataSourcesProperties.getInitialSize();
        Integer dbMinIdle = multipleDataSourcesProperties.getMinIdle();
        Integer dbMaxActive = multipleDataSourcesProperties.getMaxActive();
        String dbMasterConfig = multipleDataSourcesProperties.getMasterConfig();

        // 环境配置
        Environment env = Apps.getEnvironment();
        initSlaveAutoInfo(env);

        MultipleDataSource dataSource = new MultipleDataSource(dbDriver, dbInitialSize, dbMinIdle, dbMaxActive, dbMasterConfig, multipleDataSourcesProperties.getSlaveConfig(),multipleDataSourcesProperties);
        return dataSource;
    }


    @Bean
    @ConditionalOnMissingBean
    public DataSource dataSource() {
        DataSource dataSource = druidProperties.build();
        return dataSource;
    }

    @Bean
    @ConditionalOnMissingBean(JdbcOperations.class)
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean
    @ConditionalOnMissingBean(NamedParameterJdbcOperations.class)
    public NamedParameterJdbcTemplate namedParameterJdbcTemplate(DataSource dataSource) {
        return new NamedParameterJdbcTemplate(dataSource);
    }

    @Bean
    @ConditionalOnProperty(name = "cayden.multiple.enable", havingValue = "true")
    public CheckDataSourceHandleAop checkDataSourceHandleAop(){
        return new CheckDataSourceHandleAop();
    }



    private Boolean checkSlaveConfigIsNull(String dbSlaveConfig) {
        return StringUtils.isBlank(dbSlaveConfig);
    }

    private void initSlaveAutoInfo(Environment env){
        String startSlaveConfig = MultipleDataSourcesProperties.SLAVE_PRO_PATH;
        String slaveWeightPath = MultipleDataSourcesProperties.SLAVE_WEIGHT_PATH;
        Integer index = 0;
        List<String> slaveConfigs = new ArrayList<>();
        Map<String,Integer> slaveWeightMap = new LinkedHashMap<>();
        while(true){
            if (index == 0){
                String dbSlaveConfig = env.getProperty(startSlaveConfig);
                String slaveWeight = env.getProperty(startSlaveConfig + slaveWeightPath);
                Boolean checkIsNull = checkSlaveConfigIsNull(dbSlaveConfig);
                if (checkIsNull){
                    // 这里尝试一下就是规范使用错误的办法
                    index ++;
                    continue;
                }
                multipleDataSourcesProperties.setSlaveIndexHasZeoStart(true);
                slaveConfigs.add(dbSlaveConfig);
                if (StringUtils.isBlank(slaveWeight)){
                    slaveWeightMap.put("slave_0",1);
                }else{
                    slaveWeightMap.put(startSlaveConfig + slaveWeightPath,Integer.valueOf(slaveWeight));
                }
                index ++;
            }

            if (index > 0){
                String dbSlaveConfig = env.getProperty(startSlaveConfig + index);
                String slaveWeight = env.getProperty(startSlaveConfig + index + slaveWeightPath);
                Boolean checkIsNull = checkSlaveConfigIsNull(dbSlaveConfig);
                if (checkIsNull){
                    break;
                }
                slaveConfigs.add(dbSlaveConfig);
                if (StringUtils.isBlank(slaveWeight)){
                    slaveWeightMap.put("slave_" + index,1);
                }else{
                    slaveWeightMap.put("slave_" + index,Integer.valueOf(slaveWeight));
                }
                index ++;
            }
        }

        // 为了数据源的一致性,这里都采用 multipleDataSourcesProperties
        multipleDataSourcesProperties.setSlaveConfig(slaveConfigs);
        multipleDataSourcesProperties.setSlaveWeightConfig(slaveWeightMap);
    }

}
